package findutil
import (
"encoding/xml"
"github.com/ChrisTrenkamp/goxpath/parser/pathexpr"
"github.com/ChrisTrenkamp/goxpath/tree"
"github.com/ChrisTrenkamp/goxpath/xconst"
)
const (
wildcard = "*"
)
type findFunc func (tree .Node , *pathexpr .PathExpr , *[]tree .Node )
var findMap = map [string ]findFunc {
xconst .AxisAncestor : findAncestor ,
xconst .AxisAncestorOrSelf : findAncestorOrSelf ,
xconst .AxisAttribute : findAttribute ,
xconst .AxisChild : findChild ,
xconst .AxisDescendent : findDescendent ,
xconst .AxisDescendentOrSelf : findDescendentOrSelf ,
xconst .AxisFollowing : findFollowing ,
xconst .AxisFollowingSibling : findFollowingSibling ,
xconst .AxisNamespace : findNamespace ,
xconst .AxisParent : findParent ,
xconst .AxisPreceding : findPreceding ,
xconst .AxisPrecedingSibling : findPrecedingSibling ,
xconst .AxisSelf : findSelf ,
}
func Find (x tree .Node , p pathexpr .PathExpr ) []tree .Node {
ret := []tree .Node {}
if p .Axis == "" {
findChild (x , &p , &ret )
return ret
}
f := findMap [p .Axis ]
f (x , &p , &ret )
return ret
}
func findAncestor(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
if x .GetNodeType () == tree .NtRoot {
return
}
addNode (x .GetParent (), p , ret )
findAncestor (x .GetParent (), p , ret )
}
func findAncestorOrSelf(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
findSelf (x , p , ret )
findAncestor (x , p , ret )
}
func findAttribute(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
if ele , ok := x .(tree .Elem ); ok {
for _ , i := range ele .GetAttrs () {
addNode (i , p , ret )
}
}
}
func findChild(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
if ele , ok := x .(tree .Elem ); ok {
ch := ele .GetChildren ()
for i := range ch {
addNode (ch [i ], p , ret )
}
}
}
func findDescendent(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
if ele , ok := x .(tree .Elem ); ok {
ch := ele .GetChildren ()
for i := range ch {
addNode (ch [i ], p , ret )
findDescendent (ch [i ], p , ret )
}
}
}
func findDescendentOrSelf(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
findSelf (x , p , ret )
findDescendent (x , p , ret )
}
func findFollowing(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
if x .GetNodeType () == tree .NtRoot {
return
}
par := x .GetParent ()
ch := par .GetChildren ()
i := 0
for x != ch [i ] {
i ++
}
i ++
for i < len (ch ) {
findDescendentOrSelf (ch [i ], p , ret )
i ++
}
findFollowing (par , p , ret )
}
func findFollowingSibling(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
if x .GetNodeType () == tree .NtRoot {
return
}
par := x .GetParent ()
ch := par .GetChildren ()
i := 0
for x != ch [i ] {
i ++
}
i ++
for i < len (ch ) {
findSelf (ch [i ], p , ret )
i ++
}
}
func findNamespace(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
if ele , ok := x .(tree .NSElem ); ok {
ns := tree .BuildNS (ele )
for _ , i := range ns {
addNode (i , p , ret )
}
}
}
func findParent(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
if x .GetNodeType () != tree .NtRoot {
addNode (x .GetParent (), p , ret )
}
}
func findPreceding(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
if x .GetNodeType () == tree .NtRoot {
return
}
par := x .GetParent ()
ch := par .GetChildren ()
i := len (ch ) - 1
for x != ch [i ] {
i --
}
i --
for i >= 0 {
findDescendentOrSelf (ch [i ], p , ret )
i --
}
findPreceding (par , p , ret )
}
func findPrecedingSibling(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
if x .GetNodeType () == tree .NtRoot {
return
}
par := x .GetParent ()
ch := par .GetChildren ()
i := len (ch ) - 1
for x != ch [i ] {
i --
}
i --
for i >= 0 {
findSelf (ch [i ], p , ret )
i --
}
}
func findSelf(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
addNode (x , p , ret )
}
func addNode(x tree .Node , p *pathexpr .PathExpr , ret *[]tree .Node ) {
add := false
tok := x .GetToken ()
switch x .GetNodeType () {
case tree .NtAttr :
add = evalAttr (p , tok .(xml .Attr ))
case tree .NtChd :
add = evalChd (p )
case tree .NtComm :
add = evalComm (p )
case tree .NtElem , tree .NtRoot :
add = evalEle (p , tok .(xml .StartElement ))
case tree .NtNs :
add = evalNS (p , tok .(xml .Attr ))
case tree .NtPi :
add = evalPI (p )
}
if add {
*ret = append (*ret , x )
}
}
func evalAttr(p *pathexpr .PathExpr , a xml .Attr ) bool {
if p .NodeType == "" {
if p .Name .Space != wildcard {
if a .Name .Space != p .NS [p .Name .Space ] {
return false
}
}
if p .Name .Local == wildcard && p .Axis == xconst .AxisAttribute {
return true
}
if p .Name .Local == a .Name .Local {
return true
}
} else {
if p .NodeType == xconst .NodeTypeNode {
return true
}
}
return false
}
func evalChd(p *pathexpr .PathExpr ) bool {
if p .NodeType == xconst .NodeTypeText || p .NodeType == xconst .NodeTypeNode {
return true
}
return false
}
func evalComm(p *pathexpr .PathExpr ) bool {
if p .NodeType == xconst .NodeTypeComment || p .NodeType == xconst .NodeTypeNode {
return true
}
return false
}
func evalEle(p *pathexpr .PathExpr , ele xml .StartElement ) bool {
if p .NodeType == "" {
return checkNameAndSpace (p , ele )
}
if p .NodeType == xconst .NodeTypeNode {
return true
}
return false
}
func checkNameAndSpace(p *pathexpr .PathExpr , ele xml .StartElement ) bool {
if p .Name .Local == wildcard && p .Name .Space == "" {
return true
}
if p .Name .Space != wildcard && ele .Name .Space != p .NS [p .Name .Space ] {
return false
}
if p .Name .Local == wildcard && p .Axis != xconst .AxisAttribute && p .Axis != xconst .AxisNamespace {
return true
}
if p .Name .Local == ele .Name .Local {
return true
}
return false
}
func evalNS(p *pathexpr .PathExpr , ns xml .Attr ) bool {
if p .NodeType == "" {
if p .Name .Space != "" && p .Name .Space != wildcard {
return false
}
if p .Name .Local == wildcard && p .Axis == xconst .AxisNamespace {
return true
}
if p .Name .Local == ns .Name .Local {
return true
}
} else {
if p .NodeType == xconst .NodeTypeNode {
return true
}
}
return false
}
func evalPI(p *pathexpr .PathExpr ) bool {
if p .NodeType == xconst .NodeTypeProcInst || p .NodeType == xconst .NodeTypeNode {
return true
}
return false
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .